<?php

/**
 * 订单业务逻辑
 */

namespace app\client\services;

use app\admin\model\AdminModel;
use app\admin\model\ExpressOrderModel;
use app\admin\model\OrderInModel;
use app\admin\model\RecyclePointModel;
use app\admin\model\ShopModel;
use think\facade\Db;
use think\facade\Validate;

class OrderService
{
    /**
     * 下单
     * @param $p
     * @return void
     */
    public static function in($p)
    {
        $rule=[
            'address'=>'require',
            'appointment_time'=>'require',
            'weight'=>'require',
            'phone'=>'require',
            'lat'=>'require',
            'lng'=>'require',
        ];
        if(!strInArray($p['address'],['江苏','浙江','上海','安徽','山东','广东']))
            api_return('500','所在省份暂不可下单');
        if(strInArray($p['address'],['村','镇','县']))
            api_return('500','所在城市暂不可下单');

        $validate=Validate::rule($rule);
        if(!$validate->check($p)){
            api_return(500,$validate->getError());
        }
//        self::pushOrder2Shop($p);
        self::pushOrder2RecyclePoint($p);

    }

    /**
     * 订单详情
     * @param $p
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function detail($p){
        $rule=[
            'id'=>'require',
        ];
        $validate=Validate::rule($rule);
        if(!$validate->check($p)){
            api_return(500,$validate->getError());
        }
        if(!$orderInfo=OrderInModel::find($p['id']))
        {
            api_return(500,'订单不存在');
        }
        $orderInfo->riderInfo=AdminModel::field('nickname,phone')->find($orderInfo->admin_id);
        api_return(200,'',$orderInfo);
    }

    /**
     * 取消订单
     * @param $p
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function cancel($p){
        $rule=[
            'id'=>'require',
        ];
        $validate=Validate::rule($rule);
        if(!$validate->check($p)){
            api_return(500,$validate->getError());
        }
        if(!$orderInfo=OrderInModel::field('id,status,recycle_point_id')->find($p['id']))
        {
            api_return(500,'订单不存在');
        }
        if($orderInfo->status!=1){
            api_return(500,'订单已接单，状态不可更改');
        }
        if($orderInfo->recycle_point_id){
            $expressInfo=ExpressOrderModel::where([
                ['order_in_id','=',$p['id']]
            ])->find();
            JDService::CancelOrder($expressInfo->waybillCode,$expressInfo->orderCode);
        }
        $orderInfo->status=5;
        api_return(($orderInfo->save())?200:500);
    }

    /**
     * 订单列表
     * @param $p
     * @return void
     */
    public static function list($p){
       $params=[
           'where'=>[
               ['customer_id','=',$p['customer_id']]
           ],
           'page'=>($p['page'])??1,
           'pageSize'=>($p['pageSize'])??10,
           'field'=>'id,orderid,weight,status,appointment_time,create_time'
       ];
       if(!empty($p['status'])){
           $params['where'][]=[
               'status','=',$p['status']
           ];
       }
       $list=OrderInModel::getList($params);
       $count=OrderInModel::count($params['where']);
       api_return(200,'',['list'=>$list,'count'=>$count]);
    }

    protected static function allotRider($shop_id){
        $riderList=AdminModel::where([
            ['shop_id','=',$shop_id],
            ['status','=',1],
            ['openid','<>',''],
            ['role','=',3]
        ])->field('id,phone')->with([
            'order'=>function($query){
                return $query->where([
                    ['status','in',[1,2]],
                ])->withField(['count(id) as count','admin_id']);
            }
        ])->select()->toArray();
        if(empty($riderList)){
            api_return(500,'暂无回收员接单');
        }
        foreach ($riderList as $k=>$item){
            $riderList[$k]['orderCount']=count($item['order']);
        }
        array_multisort(array_column($riderList,'orderCount'),SORT_ASC ,$riderList);
        return [
            'id'=>$riderList[0]['id'],
            'phone'=>$riderList[0]['phone'],
        ];
    }

    /**
     * 发送订单到回收站业务逻辑
     * @param $p
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected static function pushOrder2Shop($p){
        $field='id,owner_id,6378.138 * 2 * ASIN(
            SQRT(
                POW(
                    SIN(
                        (
                            "'.$p['lat'].'" * PI() / 180 - lat * PI() / 180
                        ) / 2
                    ),
                    2
                ) + COS("'.$p['lng'].'" * PI() / 180) * COS(lng * PI() / 180) * POW(
                    SIN(
                        (
                            "'.$p['lng'].'" * PI() / 180 - lng * PI() / 180
                        ) / 2
                    ),
                    2
                )
            )
        ) AS distance';
        $shopInfo=ShopModel::field($field)->order('distance')->find();
        $p['distance']=round($shopInfo->distance,2);
        if($p['distance']>3){
            api_return(500,'您附近没有回收点');
        }
        $p['shop_id']=$shopInfo->id;
        $p['status']=1;
        $p['unit_price']=config('unitPrice')['cloth'];
        $riderInfo=self::allotRider($shopInfo->id);
        $p['admin_id']=$riderInfo['id'];
        $res=OrderInModel::editWithReturn($p);
        if($res){
            AliBaBaCloudService::sendSmsToStationManager($riderInfo['phone'],$p['weight'],$p['address'],$p['appointment_time']);
            api_return(200,'',$res);
        }else{
            api_return(500,'',$res);
        }
    }

    /**
     * 发送订单到物流回收点
     * @param $p
     * @return void
     */
    protected static function pushOrder2RecyclePoint($p){
        $field='id,phone,address,owner_id,6378.138 * 2 * ASIN(
            SQRT(
                POW(
                    SIN(
                        (
                            "'.$p['lat'].'" * PI() / 180 - lat * PI() / 180
                        ) / 2
                    ),
                    2
                ) + COS("'.$p['lng'].'" * PI() / 180) * COS(lng * PI() / 180) * POW(
                    SIN(
                        (
                            "'.$p['lng'].'" * PI() / 180 - lng * PI() / 180
                        ) / 2
                    ),
                    2
                )
            )
        ) AS distance';
        $pointInfo=RecyclePointModel::field($field)->order('distance')->find();
        JDService::CheckPreCreateOrder($p['nickname'],$p['address'],$pointInfo->address);
        $p['distance']=round($pointInfo->distance,2);
        $p['shop_id']=0;
        $p['recycle_point_id']=$pointInfo->id;
        $p['status']=1;
        $p['unit_price']=config('unitPrice')['cloth'];
        Db::startTrans();
        $appointMentTime=self::getAppointmentRange($p['appointment_time']);
        $res=OrderInModel::editWithReturn($p);
        if($res){
            $result=JDService::CreateOrder(
                $res->orderid,
                $p['nickname'],
                $p['phone'],
                $p['address'],
                $pointInfo->address,
                $pointInfo->phone,
                self::getRealWeightRange($p['weight']),
                $appointMentTime['start'],
                $appointMentTime['end']
            );
            $result['data']['orderid']=$res->orderid;
            $result['data']['order_in_id']=$res->id;
            $result['data']['pickupPromiseTime']=date('Y-m-d H:i:s',$result['data']['pickupPromiseTime']/1000);
            if(!empty($result['data']['deliveryPromiseTime']))
                $result['data']['deliveryPromiseTime']=date('Y-m-d H:i:s',$result['data']['deliveryPromiseTime']/1000);
            if(ExpressOrderModel::editWithReturn($result['data'])){
                Db::commit();
                api_return(200,'',$res);
            }else{
                Db::rollback();
                api_return(500,'',$res);
            }
        }else{
            Db::rollback();
            api_return(500,'',$res);
        }
    }

    /**
     * 获取预约时段时间戳（ms）
     * @param $appointment_time
     * @return array
     */
    protected static function getAppointmentRange($appointment_time){
        $appointmentDateTime=explode(' ',$appointment_time);
        $appointmentDate=$appointmentDateTime[0];
        $appointmentTime=explode('-',$appointmentDateTime[1]);
        $start=strtotime($appointmentDate.' '.$appointmentTime[0].':00');
        $end=strtotime($appointmentDate.' '.$appointmentTime[1].':00');
        if($end<time())
            api_return(500,'请重选预约时间');
        if($start<time())
            $start=time()+40;
        if($end<=$start){
            $end+=40;
        }
        return [
            'start'=>$start*1000,
            'end'=>$end*1000,
        ];
    }

    /**
     * 获取重量区间
     * @param $pWeight 表单提交的重量参数
     * @return int
     */
    protected static function getRealWeightRange($pWeight){
        $weight=[
            '5-10KG'=>5,
            '10-20KG'=>15,
            '20-30KG'=>25,
            '30KG以上'=>30
        ];
        return $weight[$pWeight];
    }

}
